module mculib.arm.fpu;

import mculib.chip;

version(None):
/// 判定有对应总线外设
private enum bool hasBusPeriph = HasPeriph!("FPU");
static if(hasBusPeriph):
import arm.bus;
import arm.scb;
/**
    FPU control register
    See_Also: https://blog.chinaaet.com/hxw718059156/p/5100058565
*/


/// 是否拥有硬件浮点运算
private enum Have_Hardward_FPU = __traits(targetHasFeature,"fp16");

static interface FPU
{
    enum FPU_Type* mBase = Peripherals.FPU;
    
    /*
    pragma(crt_constructor,CrtPriority!(FlagCrt.ROOT,0))
    static this()
    {
        //SCB.mBase.mask_CPACR.
    }
    */
    
}


/+++
version(NONE):

import arm.misc;
import arm;
import arm.builtins;



pragma(crt_constructor)
static this()
{
    
    //FPU_CPACR.CPACR.CP.val = 0x0f;
    //FPU_CPACR

}

//import std.math.hardware:IeeeFlags;
/// FPU 类型
enum UFType
{
    /// 单精度浮点
    SinglePrecision = 0,
    /// 单精度浮点和双精度浮点
    SingleAndDoublePrecision = 1,
    /// 单精度浮点和双精度浮点和半精度浮点
    SingleAndDoubleAndHalfPrecision = 2,
    /// 单精度浮点和双精度浮点和半精度浮点和浮点运算
    SingleAndDoubleAndHalfAndFPU = 3,
}
/// FPSCR 掩码
enum FPSCR_Mask
{
    IOC = 1 << 0,   /// 无效操作
    DZC = 1 << 1,   /// 除零
    OFC = 1 << 2,   /// 溢出
    UFC = 1 << 3,   /// 下溢
    IXC = 1 << 4,   /// 无效运算
    IDC = 1 << 7,   /// 无效输入
    RMode = 1 << 22 | 1 << 23,   /// 舍入模式
    FZ = 1 << 24,   /// 无效输入
    DN = 1 << 25,   /// 无效输入
    AHP = 1 << 26,   /// 无效输入
    V = 1 << 28,   /// 无效输入
    C = 1 << 29,   /// 无效输入
    Z = 1 << 30,    /// 无效输入
    N = 1 << 31,    /// 附属条件标志
    Filter_Mask = IOC | DZC | OFC | UFC | IXC | IDC | RMode | FZ | DN | AHP | V | C | Z | N,  /// 选择掩码
    RMode_RN = 0b00, /// 舍入模式：舍入到最近的数
    RMode_RP = 0b01, /// 舍入模式：舍入到正无穷
    RMode_RM = 0b10, /// 舍入模式：舍入到负无穷
    RMode_RZ = 0b11, /// 舍入模式：舍入到零
    RMode_POS = 22,  /// 舍入模式位置
}
/// CPACR 掩码
enum CPACR_Mask
{
    CP10 = 1 << 20 | 1 << 21,   /// 协处理器10
    CP10_POS = 20,              /// 协处理器10位置
    CP11 = 1 << 22 | 1 << 23,   /// 协处理器11
    CP11_POS = 22,              /// 协处理器11位置
    Filter_Mask = CP10 | CP11,  /// 过滤掩码

    Access_Full = 0b11,         /// 全部访问
    Access_None = 0b00,         /// 全部不访问
    Access_Privileged = 0b01,   /// 特权访问
}
/// FPCCR 掩码
enum FPCCR_Mask
{
    LSPACT = 1 << 0,    /// 最后一次特权访问
    USER = 1 << 1,      /// 用户模式
    THREAD = 1 << 3,    /// 线程模式
    HFRDY = 1 << 4,     /// 半精度浮点就绪
    MMRDY = 1 << 5,     /// 双精度浮点就绪
    BFRDY = 1 << 6,     /// 单精度浮点就绪
    MONRDY = 1 << 8,    /// 监视器就绪
    LSPEN = 1 << 30,    /// 最后一次特权访问使能
    ASPEN = 1 << 31,    /// 所有特权访问使能
    Filter_Mask = LSPACT | USER | THREAD | HFRDY | MMRDY | BFRDY | MONRDY | LSPEN | ASPEN,  /// 过滤掩码
}
/// FPCAR 掩码
enum FPCAR_Mask
{
    Address = ~0b111,   /// 地址
    Filter_Mask = Address,  /// 过滤掩码
}

struct sFPSCR
{
    align(1):
    uint IOC:1;                 /// IOC 操作累积异常位
    uint DZC:1;                 /// DZC 操作累积异常位
    uint OFC:1;                 /// OFC 操作累积异常位
    uint UFC:1;                 /// UFC 操作累积异常位
    uint IXC:1;                 /// IXC 操作累积异常位
    uint :2;                    /// 保留
    uint IDC:1;                 /// IDC 操作累积异常位
    uint :8;
    uint :6;                   /// 保留
    uint RMode:2;               /// 舍入模式
    uint FZ:1;                  /// FZ 控制位
    uint DN:1;                  /// DN 默认NaN 模式控制位
    uint AHP:1;                 /// AHP 控制位
    uint :1;                    /// 保留
    uint V:1;                   /// 溢出标志
    uint C:1;                   /// 进位标志
    uint Z:1;                   /// 零标志
    uint N:1;                   /// 负标志
    ref T opCast(T:uint)() const
    {
        return *cast(T*)&this;
    }
}
debug static assert(sFPSCR.sizeof == uint.sizeof);

private
struct sFPCCR 
{
    align(1):
    uint LSPACT:1;              /// 最后一次特权访问
    uint USER:1;                /// 用户模式
    uint :1;                    /// 保留
    uint THREAD:1;              /// 线程模式
    uint HFRDY:1;               /// 半精度浮点就绪
    uint MMRDY:1;               /// 双精度浮点就绪
    uint BFRDY:1;               /// 单精度浮点就绪
    uint :1;                    /// 保留
    uint MONRDY:1;              /// 监视器就绪
    uint :7;                    /// 保留
    uint :14;                    /// 保留
    uint LSPEN:1;               /// 最后一次特权访问使能
    uint ASPEN:1;               /// 所有特权访问使能

    ref T opCast(T:uint)() const
    {
        return *cast(T*)&this;
    }
}
debug static assert(sFPCCR.sizeof == uint.sizeof);


struct sFPCAR
{
    align(1):
    uint :3;                    /// 保留
    uint Address:29;            /// 地址

    ref T opCast(T:uint)() const
    {
        return *cast(T*)&this;
    }
}
debug static assert(sFPCAR.sizeof == uint.sizeof);

struct sFPDSCR
{
    align(1):   
    uint :16;                   /// 保留
    uint :6;                    /// 保留
    uint RMode:2;               /// FPSCR.RMode
    uint FZ:1;                  /// FPSCR.DZ
    uint DN:1;                  /// FPSCR.DN
    uint AHP:1;                 /// FPSCR.AHP

    ref T opCast(T:uint)() const
    {
        return *cast(T*)&this;
    }
}
debug static assert(sFPDSCR.sizeof == uint.sizeof);


struct sMVFR0
{
    uint ASimdReg:4;      /// ASimd寄存器
    uint SinglePrecision:4;   /// 单精度浮点
    uint DoublePrecision:4;   /// 双精度浮点
    uint FPExcepTrapping:4;   /// 浮点异常
    uint Divide:4;       /// 除法
    uint SquareRoot:4;   /// 平方根
    uint ShortVectors:4; /// 短向量
    uint FPRounding:4;   /// 浮点舍入

    ref T opCast(T:uint)() const
    {
        return *cast(T*)&this;
    }
}
debug static assert(sMVFR0.sizeof == uint.sizeof);

struct sMVFR1
{
    uint FlushToZero:4;   /// 
    uint NanMode:4;       ///
    uint :8;             ///
    uint :8;             ///
    uint FP_HPFP:4;       /// 半精度浮点
    uint FusedMAC:4;      ///

    ref T opCast(T:uint)() const
    {
        return *cast(T*)&this;
    }
}
debug static assert(sMVFR1.sizeof == uint.sizeof);

/// 0xe000_ef30
struct sFPU
{
    align(1):
    uint Reserved0;             /// 保留 offset: 0x00
    sFPCCR FPCCR;               /// FPCCR offset: 0x04
    sFPCAR FPCAR;               /// FPCAR offset: 0x08
    sFPDSCR FPDSCR;             /// FPDSCR offset: 0x0c
    sMVFR0 MVFR0;               /// MVFR0 offset: 0x10
    sMVFR1 MVFR1;               /// MVFR1 offset: 0x14
}
debug static assert(sFPU.sizeof == uint.sizeof*6);


final abstract class D_FPU
{
    enum PeripheralAddress = CorePeripheralAddress.FPU_Base;
    enum CPACRAddress = CorePeripheralAddress.FPU_CPACR;

    enum pFPU = RegMap!(CorePeripheralAddress.FPU_Base,sFPU);
    /// FPSCR 寄存器值
    pragma(inline,_inline)
    @property 
    static sFPSCR Fpscr()
    {
        return cast(sFPSCR)__get_FPSCR();
    }
    pragma(inline,_inline)
    @property 
    static void Fpscr(sFPSCR v)
    {
        //set_Fpscr(v.FPSCR);
        __set_FPSCR(cast(uint)v);
    }
    /// 获取功能寄存器0
    pragma(inline,_inline)
    @property
    static sMVFR0 GetMvfr0()
    {
        return sMVFR0(ReadMemory!(&pFPU.MVFR0,uint)());
    }
    /// 获取功能寄存器1
    pragma(inline,_inline)
    @property
    static sMVFR1 GetMvfr1()
    {
        return sMVFR1(ReadMemory!(&pFPU.MVFR1,uint)());
    }
    /*
    /// 获取FPU类型
    @property
    static UFType GetFType()
    {
        // mmvfp0 
        //return UFType(ReadMemory!(&pFPU.FTYPE,uint)());
    }
    */

    static if(__traits(targetCPU) == "cortex-m7"){
        /// 获取功能寄存器2
        pragma(inline,_inline)
        @property
        static UMVFR2 GetMvfr2()
        {
            return UMVFR2(ReadMemory!(&pFPU.MVFR2,uint)());
        }
    }
    
}


/**
    浮点控制
    * 0xe000ed88 ~ 0xe000ed8b
    * 0xe000ef30 ~ 0xe000ef44
*/
final abstract class FPU
{
    enum PeripheralAddress = CorePeripheralAddress.FPU_Base;
    private
    struct FPU_Struct
    {
        /// 对齐
        align(1):
        /// 保留
        uint   Reserved0;
        /// 控制寄存器
        uint   FPCCR;
        /// 状态寄存器
        uint   FPCAR;
        /// 状态寄存器
        uint   FPDSCR;
        /// 特性寄存器0
        uint   MVFR0;
        /// 特性寄存器1
        uint   MVFR1;        
    }

    /// 寄存器控制位掩码
    enum Mask 
    {
        /// 0b0001
        FPCCR_ASPEN = combineMasks!(31),
        /// 0b0010
        FPCCR_LSPEN = combineMasks!(30),
        /// 0b0100
        FPCCR_MONRDY = combineMasks!(8),
        /// 0b1000
        FPCCR_BFRDY = combineMasks!(6),
        /// 0b10000
        FPCCR_MMRDY = combineMasks!(5),
        /// 0b100000
        FPCCR_HFRDY = combineMasks!(4),
        /// 0b1000000
        FPCCR_THREAD = combineMasks!(3),
        /// 0b10000000
        FPCCR_USER = combineMasks!(1),
        /// 0b100000000
        FPCCR_LSPACT = combineMasks!(0),
        /// 0b1000000000
        FPCCR_ASPACT = combineMasks!(0),
        /// 0b10000000000
        FPCCR_ENABLE = combineMasks!(0),
        /// 0b100000000000
        FPCCR_LSPENS = combineMasks!(0),
        /// 0b1000000000000
        FPCCR_ASPENS = combineMasks!(0),
        /// FPCCR掩码
        FPCCR = combineMasks!(31,30,8,6,5,4,3,1,0),
        /// Address Register
        FPCAR_ADR = MakerMask!(3,32),
        ///  FPCAR掩码
        FPCAR = FPCAR_ADR,
        /// 浮点状态寄存器 N
        FPSCR_N = combineMasks!(31),
        /// 浮点状态寄存器 Z
        FPSCR_Z = combineMasks!(30),
        /// 浮点状态寄存器 C
        FPSCR_C = combineMasks!(29),
        /// 浮点状态寄存器 V
        FPSCR_V = combineMasks!(28),
        /// 浮点状态寄存器 AHP
        FPSCR_AHP = combineMasks!(26),
        /// 浮点状态寄存器 DN
        FPSCR_DN = combineMasks!(25),
        /// 浮点状态寄存器 FZ
        FPSCR_FZ = combineMasks!(24),
        /// 浮点状态寄存器 RMode
        FPSCR_RMode = combineMasks!(22,23),
        /// 浮点状态寄存器 IDC
        FPSCR_IDC = combineMasks!(7),
        /// 浮点状态寄存器 IXC
        FPSCR_IXC = combineMasks!(4),
        /// 浮点状态寄存器 UFC
        FPSCR_UFC = combineMasks!(3),
        /// 浮点状态寄存器 OFC
        FPSCR_OFC = combineMasks!(2),
        /// 浮点状态寄存器 DZC
        FPSCR_DZC = combineMasks!(1),
        /// 浮点状态寄存器 IOC
        FPSCR_IOC = combineMasks!(0),
        /// FPSCR 掩码
        FPSCR = combineMasks!(31,30,29,28,26,25,24,22,23,7,4,3,2,1,0),
        /// 浮点初始化状态控制寄存器 AHP
        FPDSCR_AHP = combineMasks!(26),
        /// 浮点初始化状态控制寄存器 DN
        FPDSCR_DN = combineMasks!(25),
        /// 浮点初始化状态控制寄存器 FZ
        FPDSCR_FZ = combineMasks!(24),
        /// 浮点初始化状态控制寄存器 RMode
        FPDSCR_RMode = combineMasks!(22,23),
        /// FPDSCR 掩码
        FPDSCR = combineMasks!(26,25,24,22,23),
    }
    /// 寄存器指针
    enum FPU_Struct* pFPU = cast(FPU_Struct*)PeripheralAddress;
    /// 浮点特性寄存器 MVFR0
    static uint GetMVFR0()
    {
        //return volatileLoad(&pFPU.MVFR0);
        return ReadMemory!(&pFPU.MVFR0,uint)();
    }
    /// 浮点特性寄存器 MVFR1
    static uint GetMVFR1()
    {
        //return volatileLoad(&pFPU.MVFR1);
        return ReadMemory!(&pFPU.MVFR1,uint)();
    }

}


+++/